package pers.cz.postgirl.core;

import com.alibaba.fastjson.JSON;
import com.lmax.disruptor.RingBuffer;
import pers.cz.jefconfig.config.JefConfiguration;
import pers.cz.postgirl.config.SystemConfig;
import pers.cz.postgirl.config.SystemEnum;
import pers.cz.postgirl.config.RecordPlayType;
import pers.cz.postgirl.core.async.ProductThreadPool;
import pers.cz.postgirl.core.async.SpyDisruptorUtil;
import pers.cz.postgirl.core.async.SpyEventProducer;
import pers.cz.postgirl.core.enums.StoreEnum;
import pers.cz.postgirl.core.store.Store;
import pers.cz.postgirl.util.ContextUtils;
import pers.cz.postgirl.util.JefLog;
import pers.cz.postgirl.util.StringUtils;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * @program: postgirl-client
 * @description: 间谍处理器，负责将间谍携带回来的信息进行处理
 * @author: Cheng Zhi
 * @create: 2023-05-28 21:38
 **/
public class SpyHandler {

    private static JefLog jefLog = new JefLog(SpyHandler.class);
    public static void onHandle(Spy spy) {

        // 如果spy携带回来的是入参信息
       switch (spy.getDataType()) {
           case INPUT:
               handleInput(spy);
               break;
           case OUTPUT:
               handleOutPut(spy);
               break;
       }
    }

    public static Spy getResult(Spy spy) {

        String methodName = spy.getMethodName();
        String caseId = ContextUtils.getCaseId();
        String md5 = StringUtils.getMD5ByParam(spy.getParamValueList());
        String key = caseId + "_" + spy.getClzName() + "_" + methodName + "_" + md5;
        if (SystemConfig.getInstance().isDebug()) {
            jefLog.debug("key==== : " + key);
            jefLog.debug("spy==== :" + JSON.toJSONString(spy));
        }
        String storeStrategy = JefConfiguration.get(SystemEnum.CLIENT_STORE_STRATEGY, "local");
        Store store = StoreEnum.getStoreInstance(storeStrategy);
        Object json = store.get(key);

        Spy result = (Spy) json;

        try {
            if (SystemConfig.getInstance().isDebug()) {
                jefLog.debug("spy content：" + JSON.toJSONString(result));
                jefLog.debug("get result value from cache：" + result.getReturnValue());
                jefLog.debug("get result type from cache：" + result.getReturnType().toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 判断是否需要录制
     * @return
     */
    private static boolean judgeRecord() {

        return ContextUtils.getEle(RecordPlayType.RECORD);
    }

    /**
     * 判断是否需要回放
     * @return
     */
    public static boolean judgePlayback() {

        return ContextUtils.getEle(RecordPlayType.PLAYBACK);
    }

    private static void handleInput(Spy spy) {

        if (judgeRecord()) {
            jefLog.debug("record test case");
            // 普通方法的入参，直接塞到栈中等待出参去匹配
            ContextUtils.pushMethodStack(spy);
        }

    }

    private static void handleOutPut(Spy spy) {

        if (judgeRecord()) {
            jefLog.debug("ready to deal response");
            Spy spyInput = ContextUtils.popMethodStack();
            // 将入参和出参合并保存
            Spy merged = mergeInputAndOutput(spyInput, spy);
            RingBuffer ringBuffer = SpyDisruptorUtil.getRingBuffer();
            ThreadPoolExecutor executor = ProductThreadPool.getExecutor();
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    SpyEventProducer spyEventProducer = new SpyEventProducer(ringBuffer);
                    spyEventProducer.pushData(merged);
                }
            });
        }


    }

    private static Spy mergeInputAndOutput(Spy input, Spy output) {
        String caseId = ContextUtils.getCaseId();
        input.setCaseId(Long.valueOf(caseId));
        input.setReturnType(output.getReturnType());
        input.setRealTypeName(output.getRealTypeName()); // 保存真实的返回类型，用于后续反序列化
        input.setReturnValue(output.getReturnValue());

        return input;
    }
}
